package lib.api.bierdopje;

import java.util.ArrayList;
import java.util.List;

import lib.XML.XMLHelper;
import lib.api.XmlHTTPAPI;
import lib.api.bierdopje.model.JBierEpisode;
import lib.api.bierdopje.model.JBierShow;
import lib.api.bierdopje.model.JBierSubtitle;
import lib.logging.Logger;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class JBierdopjeApi extends XmlHTTPAPI {

	private String apiKey, apiServer;

	public JBierdopjeApi(String apiKey) {
		this(apiKey, "http://api.bierdopje.com");
		this.setUserAgent("JBierSubDownloader/4.0.17");
		this.setRatelimit(10);
		this.setDayRatelimit(300);
	}

	public JBierdopjeApi(String apiKey, String apiServer) {
		this.setApiKey(apiKey);
		this.setApiServer(apiServer);
		this.setRatelimit(10);
		this.setDayRatelimit(300);
	}

	public JBierEpisode GetEpisodeById(int episodeid) throws BierdopjeException {
		Document doc;
		// timeout 45 days
		doc = getXMLDisk(
				createApiUrl("GetEpisodeById",
						new String[] { Integer.toString(episodeid) }),
				24 * 60 * 60 * 45);
		NodeList nList = doc.getElementsByTagName("response");

		if (nList.getLength() > 0
				&& nList.item(0).getNodeType() == Node.ELEMENT_NODE) {
			return parseEpisodeNode((Element) nList.item(0));
		}

		return null;
	}

	private String createApiUrl(String command, String[] params) {
		Logger.instance.trace("JBierdopjeApi", "createApiUrl", "");
		command = command.replace("/", "");
		String urlParam = "";
		for (int i = 0; i < params.length; i++) {
			if (i == 0) {
				urlParam = params[i].replace("/", "");
			} else {
				urlParam = urlParam + "/" + params[i].replace("/", "");
			}
		}
		Logger.instance.trace("JBierdopjeApi", "createApiUrl", "create part: "
				+ "/" + command + "/" + urlParam);
		return this.apiServer + "/" + this.getApiKey() + "/" + command + "/"
				+ urlParam;
		// return this.apiServer + "/" + this.getApiKey() + "/" + command + "/"
		// + URLEncoder.encode(urlParam, "UTF-8");
	}

	private JBierEpisode parseEpisodeNode(Element eElement) {
		Logger.instance.trace("JBierdopjeApi", "parseEpisodeNode", "");

		try {
			Logger.instance.trace("JBierdopjeApi", "parseEpisodeNode",
					"Element: " + XMLHelper.getXMLAsString(eElement));
		} catch (Exception e) {
		}

		JBierEpisode ep = new JBierEpisode();
		ep.setAirdate(XMLHelper.getStringTagValue("airdate", eElement));
		// ep.setSubsen(XMLHelper.getBooleanTagValue("subsen", eElement));
		// ep.setSubsnl(XMLHelper.getBooleanTagValue("subsnl", eElement));
		ep.setEpisode(XMLHelper.getIntTagValue("episode", eElement));
		ep.setEpnumber(XMLHelper.getIntTagValue("epnumber", eElement));
		ep.setFormatted(XMLHelper.getStringTagValue("formatted", eElement));
		ep.setEpisodeid(XMLHelper.getIntTagValue("episodeid", eElement));
		ep.setEpisodelink(XMLHelper.getStringTagValue("episodelink", eElement));
		ep.setSeason(XMLHelper.getIntTagValue("season", eElement));
		ep.setIsSpecial(XMLHelper.getStringTagValue("is_special", eElement));
		ep.setTitle(XMLHelper.getStringTagValue("title", eElement));
		ep.setVotes(XMLHelper.getStringTagValue("votes", eElement));
		// ep.setWip(XMLHelper.getStringTagValue("wip", eElement));
		// ep.setWipuser(XMLHelper.getStringTagValue("wipuser", eElement));
		// ep.setWippercentage(XMLHelper.getIntTagValue("wippercentage",
		// eElement));
		ep.setSummary(XMLHelper.getStringTagValue("summary", eElement));
		ep.setTvdbid(XMLHelper.getIntTagValue("tvdbid", eElement));
		ep.setScore(XMLHelper.getStringTagValue("score", eElement));

		return ep;
	}

	public JBierShow FindShowByName(String showname) throws BierdopjeException {
		Logger.instance.trace("JBierdopjeApi", "FindShowByName", "showname: "
				+ showname);
		Document doc;
		String searchterm = XMLHelper.CleanBadChars(showname);
		final String url = createApiUrl("FindShowByName",
				new String[] { searchterm.replace(" ", "-").replace("&", "_") });
		doc = getXMLDisk(url);

		// remove chars to clean up inconsistencies in show names
		showname = cleanUpShowNames(showname);

		NodeList nList = doc.getElementsByTagName("result");

		for (int i = 0; i < nList.getLength(); i++) {
			if (nList.item(i).getNodeType() == Node.ELEMENT_NODE
					&& !nList.item(i).getParentNode().getNodeName()
							.equals("genres")) {
				Element eElement = (Element) nList.item(i);
				if (eElement != null) {
					JBierShow s = parseShowNode(eElement);
					// remove same chars as in showname
					String biershow = cleanUpShowNames(s.getName());
					// replace HTML chars
					biershow = biershow.replace("&amp;", "&").replace("'", "");
					if (biershow.compareToIgnoreCase(showname) == 0) {
						// store entry
						return s;
					}
				}
			}
		}

		try {
			Logger.instance.trace(
					"JBierdopjeApi",
					"FindShowByName",
					"Unable to Parse, Response from Bierdopje: "
							+ XMLHelper.getXMLAsString(doc));
		} catch (Exception e) {
			// do nothing
		}

		return null;
	}

	private String cleanUpShowNames(String text) {
		Logger.instance.trace("JBierdopjeApi", "cleanUpShowNames", "text: "
				+ text);
		return text.replace("(", "").replace(")", "").replace(":", "")
				.replace("'", "").replace("?", "").replace(".", "")
				.replace("- ", "");
	}

	public List<JBierEpisode> GetAllEpisodesForShow(int showid)
			throws BierdopjeException {
		List<JBierEpisode> epList = new ArrayList<JBierEpisode>();

		// timeout 7 days
		Document doc = getXMLDisk(
				createApiUrl("GetAllEpisodesForShow",
						new String[] { Integer.toString(showid) }),
				24 * 60 * 60 * 7);

		NodeList nList = doc.getElementsByTagName("result");

		for (int i = 0; i < nList.getLength(); i++) {
			if (nList.item(i).getNodeType() == Node.ELEMENT_NODE) {
				Element eElement = (Element) nList.item(i);
				JBierEpisode ep = parseEpisodeNode(eElement);
				epList.add(ep);
			}
		}

		return epList;
	}

	public List<JBierEpisode> GetEpisodesForSeason(int showid, int season)
			throws BierdopjeException {
		List<JBierEpisode> epList = new ArrayList<JBierEpisode>();

		// timeout 3 hours 60 * 60 * 3
		// timeout 15 days 24 * 60 * 60 * 15
		// timeout 7 days 24 * 60 * 60 * 7

		String seasonString;
		if (season == 0) {
			seasonString = "00";
		} else {
			seasonString = Integer.toString(season);
		}

		Document doc = getXMLDisk(
				createApiUrl("GetEpisodesForSeason",
						new String[] { Integer.toString(showid), seasonString }),
				24 * 60 * 60 * 14);

		if (doc != null) {
			NodeList nList = doc.getElementsByTagName("result");

			for (int i = 0; i < nList.getLength(); i++) {
				if (nList.item(i).getNodeType() == Node.ELEMENT_NODE) {
					Element eElement = (Element) nList.item(i);
					JBierEpisode ep = parseEpisodeNode(eElement);
					epList.add(ep);
				}
			}
		}

		return epList;
	}

	public JBierShow GetShowById(int showid) throws BierdopjeException {
		Logger.instance.trace("JBierdopjeApi", "GetShowById", "showid: "
				+ showid);
		// timeout 45 days
		Document doc = getXMLDisk(
				createApiUrl("GetShowById",
						new String[] { Integer.toString(showid) }),
				24 * 60 * 60 * 45);

		NodeList nList = doc.getElementsByTagName("response");

		if (nList.getLength() > 0
				&& nList.item(0).getNodeType() == Node.ELEMENT_NODE) {
			return parseShowNode((Element) nList.item(0));
		}
		try {
			Logger.instance.trace(
					"JBierdopjeApi",
					"GetShowById",
					"Unable to Parse, Response from Bierdopje: "
							+ XMLHelper.getXMLAsString(doc));
		} catch (Exception e) {
			// do nothing
		}
		return null;

	}

	public JBierShow GetShowByTVDBID(int showid) throws BierdopjeException {
		// timeout 45 days
		Document doc = getXMLDisk(
				createApiUrl("GetShowByTVDBID",
						new String[] { Integer.toString(showid) }),
				24 * 60 * 60 * 45);

		NodeList nList = doc.getElementsByTagName("response");

		if (nList.getLength() > 0
				&& nList.item(0).getNodeType() == Node.ELEMENT_NODE) {
			return parseShowNode((Element) nList.item(0));
		}
		return null;

	}

	private JBierShow parseShowNode(Element eElement) {
		Logger.instance.trace("JBierdopjeApi", "parseShowNode", "");
		try {
			Logger.instance.trace("JBierdopjeApi", "parseShowNode", "Element: "
					+ XMLHelper.getXMLAsString(eElement));
		} catch (Exception e) {
		}

		JBierShow show = new JBierShow();

		show.setName(XMLHelper.getStringTagValue("showname", eElement));
		show.setAirtime(XMLHelper.getStringTagValue("airtime", eElement));
		show.setEpisodes(XMLHelper.getIntTagValue("episodes", eElement));
		show.setFavorites(XMLHelper.getStringTagValue("favorites", eElement));
		show.setFirststaired(XMLHelper
				.getStringTagValue("firstaired", eElement));
		show.setLink(XMLHelper.getStringTagValue("showlink", eElement));
		show.setNetwork(XMLHelper.getStringTagValue("network", eElement));
		show.setNextepisode(XMLHelper
				.getStringTagValue("nextepisode", eElement));
		show.setRuntime(XMLHelper.getStringTagValue("runtime", eElement));
		show.setShowid(XMLHelper.getIntTagValue("showid", eElement));
		show.setSeasons(XMLHelper.getIntTagValue("seasons", eElement));
		show.setShowstatus(XMLHelper.getStringTagValue("showstatus", eElement));
		// show.setHasTranslators(XMLHelper.getBooleanTagValue("has_translators",
		// eElement));
		show.setSummary(XMLHelper.getStringTagValue("summary", eElement));
		show.setTvdbid(XMLHelper.getIntTagValue("tvdbid", eElement));
		show.setScore(XMLHelper.getStringTagValue("score", eElement));

		Logger.instance.trace("JBierdopjeApi", "parseShowNode", "Return show: "
				+ show.getName());
		return show;
	}

	public List<JBierSubtitle> GetAllSubsForEpisode(int episodeid,
			String LanguageCode) throws BierdopjeException {
		List<JBierSubtitle> subList = new ArrayList<JBierSubtitle>();
		// Document doc = getXML(this.apiServer + "/" + this.getApiKey() +
		// "/GetAllSubsForEpisode/" + episodeid + "/" + LanguageCode);
		Document doc = getXML(createApiUrl("GetAllSubsForEpisode",
				new String[] { Integer.toString(episodeid), LanguageCode }));

		if (doc != null) {
			NodeList nList = doc.getElementsByTagName("result");

			for (int i = 0; i < nList.getLength(); i++) {
				if (nList.item(0).getNodeType() == Node.ELEMENT_NODE) {
					Element eElement = (Element) nList.item(i);
					JBierSubtitle ep = parseSubtitleNode(eElement);
					subList.add(ep);
				}
			}
		}

		return subList;

	}

	public List<JBierSubtitle> GetSubsForSeason(int showid, int season,
			String LanguageCode) throws BierdopjeException {
		List<JBierSubtitle> subList = new ArrayList<JBierSubtitle>();

		String seasonString;
		if (season == 0) {
			seasonString = "00";
		} else {
			seasonString = Integer.toString(season);
		}

		Document doc = getXML(createApiUrl("GetSubsForSeason", new String[] {
				Integer.toString(showid), seasonString, LanguageCode }));

		NodeList nList = doc.getElementsByTagName("result");

		for (int i = 0; i < nList.getLength(); i++) {
			if (nList.item(0).getNodeType() == Node.ELEMENT_NODE) {
				Element eElement = (Element) nList.item(i);
				JBierSubtitle ep = parseSubtitleNode(eElement);
				subList.add(ep);
			}
		}

		return subList;

	}

	private JBierSubtitle parseSubtitleNode(Element eElement) {
		Logger.instance.trace("JBierdopjeApi", "parseSubtitleNode", "");

		try {
			Logger.instance.trace("JBierdopjeApi", "parseSubtitleNode",
					"Element: " + XMLHelper.getXMLAsString(eElement));
		} catch (Exception e) {
		}

		JBierSubtitle subtitle = new JBierSubtitle();

		subtitle.setFilename(XMLHelper.getStringTagValue("filename", eElement));
		subtitle.setDownloadcount(XMLHelper.getIntTagValue("numdownloads",
				eElement));
		subtitle.setDownloadlink(XMLHelper.getStringTagValue("downloadlink",
				eElement));
		subtitle.setFilesize(XMLHelper.getStringTagValue("filesize", eElement));
		subtitle.setPubdate(XMLHelper.getStringTagValue("pubdate", eElement));
		subtitle.setRepliescount(XMLHelper.getStringTagValue("numreplies",
				eElement));
		subtitle.setUploader(XMLHelper.getStringTagValue("uploader", eElement));

		return subtitle;
	}

	public void setApiKey(String apiKey) {
		this.apiKey = apiKey;
	}

	public String getApiKey() {
		return apiKey;
	}

	public void setApiServer(String apiServer) {
		this.apiServer = apiServer;
	}

	public String getApiServer() {
		return apiServer;
	}

	private Document checkDocumentForError(Document doc, String url)
			throws BierdopjeException {
		NodeList nList = doc.getElementsByTagName("error_code");
		if (nList.getLength() == 0) {
			return doc;
		} else {
			removeCacheEntry(url);
			String xmlString = "XML could not be parsed to String";
			try {
				xmlString = XMLHelper.getXMLAsString(doc);
			} catch (Exception e) {
			}
			throw new BierdopjeException(
					"Error Code found in the anwser from bierdopje", xmlString);
		}
	}

	protected Document getCheckedXML(String url) throws BierdopjeException {
		setUserAgent("JBierSubDownloader/4.0.9");
		setRatelimit(10);
		Document doc = getXML(url);
		return checkDocumentForError(doc, url);
	}

	protected Document getCheckedXML(String url, long timeout)
			throws BierdopjeException {
		setUserAgent("JBierSubDownloader/4.0.9");
		setRatelimit(10);
		Document doc = getXML(url, timeout);
		return checkDocumentForError(doc, url);
	}

	protected Document getCheckedXMLDisk(String url) throws BierdopjeException {
		setUserAgent("JBierSubDownloader/4.0.9");
		setRatelimit(10);
		Document doc = getXMLDisk(url);
		return checkDocumentForError(doc, url);
	}

	protected Document getCheckedXMLDisk(String url, long timeout)
			throws BierdopjeException {
		setUserAgent("JBierSubDownloader/4.0.9");
		setRatelimit(10);
		Document doc = getXMLDisk(url, timeout);
		return checkDocumentForError(doc, url);
	}
}
